﻿using System;
using System.Activities;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;

using Microsoft.VisualStudio.TestTools.UnitTesting;

using Qetza.TeamFoundation.Build.Workflow.Activities;


namespace Qetza.TeamFoundation.Build.Workflow
{
    [TestClass]
    public class UpdateAssemblyInfoFileTest
    {
        #region Properties

        public TestContext TestContext { get; set; }

        #endregion

        #region Setup / Cleanup

        [TestCleanup]
        public void TestCleanup()
        {
            if (File.Exists("AssemblyInfo.cs"))
            {
                File.Delete("AssemblyInfo.cs");
            }
        }

        #endregion

        #region Tests

        [TestMethod]
        public void ExecuteWithAssemblyVersionFormatOnlyTest()
        {
            // arrange
            CopyFile("TestAssemblyInfo.cs");

            var activity = new UpdateAssemblyInfoFile();
            var parameters = new Dictionary<string, object>() {
                { "FilePath", "AssemblyInfo.cs" },
                { "AssemblyVersionFormat", "1.0.0.0" }
                };
            
            // act
            var actual = WorkflowInvoker.Invoke(activity, parameters);
            var text = File.ReadAllText("AssemblyInfo.cs");

            // assert
            Assert.AreEqual(parameters["AssemblyVersionFormat"].ToString(), actual["AssemblyVersion"].ToString());
            Assert.AreEqual("3.4.0.0", actual["AssemblyFileVersion"].ToString());
            Assert.AreEqual("Test 3.4.0.0 010101", actual["AssemblyInformationalVersion"].ToString());

            Assert.AreNotEqual(-1, text.IndexOf("[assembly: AssemblyVersion(\"1.0.0.0\")]"));
            Assert.AreNotEqual(-1, text.IndexOf("[assembly: AssemblyFileVersion(\"3.4.0.0\")]"));
            Assert.AreNotEqual(-1, text.IndexOf("[assembly: AssemblyInformationalVersion(\"Test 3.4.0.0 010101\")]"));
        }

        [TestMethod]
        public void ExecuteWithAssemblyFileVersionFormatOnlyTest()
        {
            // arrange
            CopyFile("TestAssemblyInfo.cs");

            var activity = new UpdateAssemblyInfoFile();
            var parameters = new Dictionary<string, object>() {
                { "FilePath", "AssemblyInfo.cs" },
                { "AssemblyFileVersionFormat", "1.0.0.0" }
                };

            // act
            var actual = WorkflowInvoker.Invoke(activity, parameters);
            var text = File.ReadAllText("AssemblyInfo.cs");

            // assert
            Assert.AreEqual(parameters["AssemblyFileVersionFormat"].ToString(), actual["AssemblyFileVersion"].ToString());
            Assert.AreEqual("2.1.0.0", actual["AssemblyVersion"].ToString());
            Assert.AreEqual("Test 3.4.0.0 010101", actual["AssemblyInformationalVersion"].ToString());

            Assert.AreNotEqual(-1, text.IndexOf("[assembly: AssemblyVersion(\"2.1.0.0\")]"));
            Assert.AreNotEqual(-1, text.IndexOf("[assembly: AssemblyFileVersion(\"1.0.0.0\")]"));
            Assert.AreNotEqual(-1, text.IndexOf("[assembly: AssemblyInformationalVersion(\"Test 3.4.0.0 010101\")]"));
        }

        [TestMethod]
        public void ExecuteWithAssemblyInformationalVersionFormatOnlyTest()
        {
            // arrange
            CopyFile("TestAssemblyInfo.cs");

            var activity = new UpdateAssemblyInfoFile();
            var parameters = new Dictionary<string, object>() {
                { "FilePath", "AssemblyInfo.cs" },
                { "AssemblyInformationalVersionFormat", "Test 1.0.0.0" }
                };

            // act
            var actual = WorkflowInvoker.Invoke(activity, parameters);
            var text = File.ReadAllText("AssemblyInfo.cs");

            // assert
            Assert.AreEqual(parameters["AssemblyInformationalVersionFormat"].ToString(), actual["AssemblyInformationalVersion"].ToString());
            Assert.AreEqual("2.1.0.0", actual["AssemblyVersion"].ToString());
            Assert.AreEqual("3.4.0.0", actual["AssemblyFileVersion"].ToString());

            Assert.AreNotEqual(-1, text.IndexOf("[assembly: AssemblyVersion(\"2.1.0.0\")]"));
            Assert.AreNotEqual(-1, text.IndexOf("[assembly: AssemblyFileVersion(\"3.4.0.0\")]"));
            Assert.AreNotEqual(-1, text.IndexOf("[assembly: AssemblyInformationalVersion(\"Test 1.0.0.0\")]"));
        }

        [TestMethod]
        public void ExecuteWithoutAssemblyVersionFormatTest()
        {
            // arrange
            CopyFile("TestAssemblyInfoWithoutAssemblyVersion.cs");

            var activity = new UpdateAssemblyInfoFile();
            var parameters = new Dictionary<string, object>() {
                { "FilePath", "AssemblyInfo.cs" },
                { "AssemblyFileVersionFormat", "1.0.0.0" }
                };

            // act
            var actual = WorkflowInvoker.Invoke(activity, parameters);
            var text = File.ReadAllText("AssemblyInfo.cs");

            // assert
            Assert.AreEqual(parameters["AssemblyFileVersionFormat"].ToString(), actual["AssemblyFileVersion"].ToString());
            Assert.IsNull(actual["AssemblyVersion"]);

            Assert.AreNotEqual(-1, text.IndexOf("[assembly: AssemblyFileVersion(\"1.0.0.0\")]"));
        }

        [TestMethod]
        public void ExecuteWithoutAssemblyFileVersionFormatTest()
        {
            // arrange
            CopyFile("TestAssemblyInfoWithoutAssemblyFileVersion.cs");

            var activity = new UpdateAssemblyInfoFile();
            var parameters = new Dictionary<string, object>() {
                { "FilePath", "AssemblyInfo.cs" },
                { "AssemblyVersionFormat", "1.0.0.0" }
                };

            // act
            var actual = WorkflowInvoker.Invoke(activity, parameters);
            var text = File.ReadAllText("AssemblyInfo.cs");

            // assert
            Assert.AreEqual(parameters["AssemblyVersionFormat"].ToString(), actual["AssemblyVersion"].ToString());
            Assert.IsNull(actual["AssemblyFileVersion"]);

            Assert.AreNotEqual(-1, text.IndexOf("[assembly: AssemblyVersion(\"1.0.0.0\")]"));
        }

        [TestMethod]
        public void ExecuteWithoutAssemblyInformationalVersionFormatTest()
        {
            // arrange
            CopyFile("TestAssemblyInfoWithoutAssemblyInformationalVersion.cs");

            var activity = new UpdateAssemblyInfoFile();
            var parameters = new Dictionary<string, object>() {
                { "FilePath", "AssemblyInfo.cs" },
                { "AssemblyVersionFormat", "1.0.0.0" }
                };

            // act
            var actual = WorkflowInvoker.Invoke(activity, parameters);
            var text = File.ReadAllText("AssemblyInfo.cs");

            // assert
            Assert.AreEqual(parameters["AssemblyVersionFormat"].ToString(), actual["AssemblyVersion"].ToString());
            Assert.IsNull(actual["AssemblyInformationalVersion"]);

            Assert.AreNotEqual(-1, text.IndexOf("[assembly: AssemblyVersion(\"1.0.0.0\")]"));
        }

        [TestMethod]
        public void ExecuteWithCurrentTokenTest()
        {
            // arrange
            CopyFile("TestAssemblyInfo.cs");

            var activity = new UpdateAssemblyInfoFile();
            var parameters = new Dictionary<string, object>() {
                { "FilePath", "AssemblyInfo.cs" },
                { "AssemblyVersionFormat", "$(current).0.0.0" }
                };

            // act
            var actual = WorkflowInvoker.Invoke(activity, parameters);
            var text = File.ReadAllText("AssemblyInfo.cs");

            // assert
            Assert.AreEqual("2.0.0.0", actual["AssemblyVersion"].ToString());

            Assert.AreNotEqual(-1, text.IndexOf("[assembly: AssemblyVersion(\"2.0.0.0\")]"));
        }

        [TestMethod]
        public void ExecuteWithIncrementTokenTest()
        {
            // arrange
            CopyFile("TestAssemblyInfo.cs");

            var activity = new UpdateAssemblyInfoFile();
            var parameters = new Dictionary<string, object>() {
                { "FilePath", "AssemblyInfo.cs" },
                { "AssemblyVersionFormat", "$(increment).0.0.0" }
                };

            // act
            var actual = WorkflowInvoker.Invoke(activity, parameters);
            var text = File.ReadAllText("AssemblyInfo.cs");

            // assert
            Assert.AreEqual("3.0.0.0", actual["AssemblyVersion"].ToString());

            Assert.AreNotEqual(-1, text.IndexOf("[assembly: AssemblyVersion(\"3.0.0.0\")]"));
        }

        [TestMethod]
        public void ExecuteWithDateTokenTest()
        {
            // arrange
            CopyFile("TestAssemblyInfo.cs");

            var activity = new UpdateAssemblyInfoFile();
            var parameters = new Dictionary<string, object>() {
                { "FilePath", "AssemblyInfo.cs" },
                { "AssemblyVersionFormat", "$(date:yyyyMMdd).0.0.0" }
                };

            // act
            var actual = WorkflowInvoker.Invoke(activity, parameters);
            var text = File.ReadAllText("AssemblyInfo.cs");

            // assert
            Assert.AreEqual(string.Format("{0:yyyyMMdd}.0.0.0", DateTime.Today), actual["AssemblyVersion"].ToString());

            Assert.AreNotEqual(-1, text.IndexOf(string.Format("[assembly: AssemblyVersion(\"{0:yyyyMMdd}.0.0.0\")]", DateTime.Today)));
        }

        [TestMethod]
        public void ExecuteWithVersionTokenTest()
        {
            // arrange
            CopyFile("TestAssemblyInfo.cs");

            var activity = new UpdateAssemblyInfoFile();
            var parameters = new Dictionary<string, object>() {
                { "FilePath", "AssemblyInfo.cs" },
                { "AssemblyInformationalVersionFormat", "Test $(version)" }
                };

            // act
            var actual = WorkflowInvoker.Invoke(activity, parameters);
            var text = File.ReadAllText("AssemblyInfo.cs");

            // assert
            Assert.AreEqual("Test 2.1.0.0", actual["AssemblyInformationalVersion"].ToString());

            Assert.AreNotEqual(-1, text.IndexOf("[assembly: AssemblyInformationalVersion(\"Test 2.1.0.0\")]"));
        }

        [TestMethod]
        public void ExecuteWithFileVersionTokenTest()
        {
            // arrange
            CopyFile("TestAssemblyInfo.cs");

            var activity = new UpdateAssemblyInfoFile();
            var parameters = new Dictionary<string, object>() {
                { "FilePath", "AssemblyInfo.cs" },
                { "AssemblyInformationalVersionFormat", "Test $(fileversion)" }
                };

            // act
            var actual = WorkflowInvoker.Invoke(activity, parameters);
            var text = File.ReadAllText("AssemblyInfo.cs");

            // assert
            Assert.AreEqual("Test 3.4.0.0", actual["AssemblyInformationalVersion"].ToString());

            Assert.AreNotEqual(-1, text.IndexOf("[assembly: AssemblyInformationalVersion(\"Test 3.4.0.0\")]"));
        }

        [TestMethod]
        [ExpectedException(typeof(FormatException))]
        public void ExecuteWithInvalidDateFormatTest()
        {
            // arrange
            CopyFile("TestAssemblyInfo.cs");

            var activity = new UpdateAssemblyInfoFile();
            var parameters = new Dictionary<string, object>() {
                { "FilePath", "AssemblyInfo.cs" },
                { "AssemblyVersionFormat", "$(date:invalid).0.0.0" }
                };

            // act
            var actual = WorkflowInvoker.Invoke(activity, parameters);
        }

        [TestMethod]
        [ExpectedException(typeof(FormatException))]
        public void ExecuteWithInvalidDateTokenTest()
        {
            // arrange
            CopyFile("TestAssemblyInfo.cs");

            var activity = new UpdateAssemblyInfoFile();
            var parameters = new Dictionary<string, object>() {
                { "FilePath", "AssemblyInfo.cs" },
                { "AssemblyVersionFormat", "$(date:yyyy-MM-dd).0.0.0" }
                };

            // act
            var actual = WorkflowInvoker.Invoke(activity, parameters);
        }

        [TestMethod]
        [ExpectedException(typeof(FormatException))]
        public void ExecuteWithUnknownTokenTest()
        {
            // arrange
            CopyFile("TestAssemblyInfo.cs");

            var activity = new UpdateAssemblyInfoFile();
            var parameters = new Dictionary<string, object>() {
                { "FilePath", "AssemblyInfo.cs" },
                { "AssemblyVersionFormat", "$(unknown).0.0.0" }
                };

            // act
            var actual = WorkflowInvoker.Invoke(activity, parameters);
        }

        [TestMethod]
        [ExpectedException(typeof(FormatException))]
        public void ExecuteWithInvalidVersionFormatTest()
        {
            // arrange
            CopyFile("TestAssemblyInfo.cs");

            var activity = new UpdateAssemblyInfoFile();
            var parameters = new Dictionary<string, object>() {
                { "FilePath", "AssemblyInfo.cs" },
                { "AssemblyVersionFormat", "1.0.0" }
                };

            // act
            var actual = WorkflowInvoker.Invoke(activity, parameters);
        }

        #endregion

        #region Private Helpers

        private static void CopyFile(string filePath)
        {
            File.Copy(filePath, "AssemblyInfo.cs", true);
        }

        #endregion
    }
}
